package com.lmk.ms.common.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 文本处理工具
 *
 * @author laomake@hotmail.com
 * @version 1.0
 * @date 2022/02/16
 */
@Slf4j
public class TextUtils {
    /**
     * 正则表达式：手机号
     */
    public static final String REGEX_MOBILE = "^((1[3-8][0-9]))\\d{8}$";

    /**
     * 正则表达式：邮件地址
     */
    public static final String REGEX_EMAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";

    /**
     * 正则表达式：URL地址
     */
    public static final String REGEX_URL = "[http|https]+[://]+[0-9A-Za-z:/[-]_#[?][=][.][&]]*";

    /**
     * 正则表达式：身份证号18位
     */
    public static final String REGEX_ID_CARD = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$";

    /**
     * 正则表达式：身份证号15位
     */
    public static final String REGEX_ID_CARD_OLD = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";

    /**
     * 正则表达式：整数
     */
    public static final String REGEX_NUMBER = "\\d*";

    /** 数字匹配 */
    private static Pattern NUMBER_PATTERN = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+");

    /** Unicode字符匹配 */
    private static final Pattern PATTERN_UNICODE = Pattern.compile("(\\\\u(\\w{4}))");

    /**
     * 正则表达式：包含中文
     */
    public static final String REGEX_CHINESS = "^.*[\\u4e00-\\u9fa5]+.*$";

    /**
     * 正则表达式：全为中文
     */
    public static final String REGEX_CHINESS_ALL = "[\\u4e00-\\u9fa5]{2,25}";

    /**
     * 正则表达式：手机浏览器
     */
    public static final String REGEX_UA_PHONE = "\\b(ip(hone|od)|android|opera m(ob|in)i|windows (phone|ce)|blackberry|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp|laystation portable)|nokia|fennec|htc[-_]|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";

    /**
     * 正则表达式：平板浏览器
     */
    public static final String REGEX_UA_TAB = "\\b(ipad|tablet|(Nexus 7)|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";

    /**
     * 正则表达式：用户名（字母开头的6~16位字符串，可包含：数字、字母、下划线）
     */
    public static String REGEX_USER_NAME = "^[a-zA-Z]{1}([a-zA-Z0-9]|[_]){5,15}$";

    /**
     * 正则表达式：密码（6~20位的字符串，可包含字母、数字、特殊符号，不能为纯数字）
     */
    public static String REGEX_PASSWORD = "(?!^(\\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\\w~!@#$%\\^&*?]{6,20}$";

    private static final Pattern Mobile = Pattern.compile(REGEX_MOBILE);
    private static final Pattern Email = Pattern.compile(REGEX_EMAIL);
    private static final Pattern Url = Pattern.compile(REGEX_URL);
    private static final Pattern IDcard = Pattern.compile(REGEX_ID_CARD);
    private static final Pattern IDcardOld = Pattern.compile(REGEX_ID_CARD_OLD);
    private static final Pattern Number = Pattern.compile(REGEX_NUMBER);
    private static final Pattern Chiness = Pattern.compile(REGEX_CHINESS);
    private static final Pattern ChinessAll = Pattern.compile(REGEX_CHINESS_ALL);
    private static final Pattern FromPhone = Pattern.compile(REGEX_UA_PHONE);
    private static final Pattern FromTab = Pattern.compile(REGEX_UA_TAB);
    private static Pattern UserName = Pattern.compile(REGEX_USER_NAME);
    private static Pattern Password = Pattern.compile(REGEX_PASSWORD);

    /** 汉语转拼音格式配置 */
    private static HanyuPinyinOutputFormat PinyinFormat;
    static {
        PinyinFormat = new HanyuPinyinOutputFormat();
        PinyinFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);// 输出拼音全部小写
        PinyinFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);// 不带声调
        PinyinFormat.setVCharType(HanyuPinyinVCharType.WITH_V) ;
    }

    /**
     * 首字母变小写
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     * @date 2014年10月24日
     */
    public static String firstCharToLowerCase(final String str) {
        Character firstChar = str.charAt(0);
        String tail = str.substring(1);
        return Character.toLowerCase(firstChar) + tail;
    }

    /**
     * 首字母变大写
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     * @date 2014年10月24日
     */
    public static String firstCharToUpperCase(final String str) {
        Character firstChar = str.charAt(0);
        String tail = str.substring(1);
        return Character.toUpperCase(firstChar) + tail;
    }

    /**
     * 中文转拼音
     * @param text
     * @return
     */
    public static String getPinyin(String text){
        if(StringUtils.isBlank(text)){
            return null;
        }
        StringBuilder sb = new StringBuilder();

        char[] chars = text.trim().toCharArray();
        try {
            for (int i=0; i<chars.length; i++){
                if (String.valueOf(chars[i]).matches("[\u4e00-\u9fa5]+")){// 如果字符是中文,则将中文转为汉语拼音
                    sb.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], PinyinFormat)[0]);
                } else {// 如果字符不是中文,则不转换
                    sb.append(chars[i]);
                }
            }
        } catch (BadHanyuPinyinOutputFormatCombination e) {
            log.error("中文转拼音异常：", e);
        }
        return sb.toString();
    }

    /**
     * 获取首个字符的拼音（小写）
     * @param text
     * @return
     */
    public static String getFirstPinyin(String text){
        return getFirstPinyin(text, HanyuPinyinCaseType.LOWERCASE);
    }

    /**
     * 获取首个字符的拼音的首字母（小写）
     * @param text
     * @return
     */
    public static String getFirstPinyinChar(String text){
        return getFirstPinyinChar(text, HanyuPinyinCaseType.LOWERCASE);
    }

    /**
     * 获取首个字符的拼音
     * @param text
     * @param caseType 大小写类型
     * @return
     */
    public static String getFirstPinyin(String text, HanyuPinyinCaseType caseType){
        if(StringUtils.isBlank(text)){
            return null;
        }
        String py = getPinyin(String.valueOf(text.trim().toCharArray()[0]));
        if(StringUtils.isBlank(py)){
            return null;
        }
        if(caseType == HanyuPinyinCaseType.UPPERCASE){
            py = py.toUpperCase();
        }
        return py;
    }

    /**
     * 获取首个字符的拼音的首字母
     * @param text
     * @param caseType 大小写类型
     * @return
     */
    public static String getFirstPinyinChar(String text, HanyuPinyinCaseType caseType){
        if(StringUtils.isBlank(text)){
            return null;
        }
        String py = getFirstPinyin(text, caseType);
        if(StringUtils.isBlank(py)){
            return null;
        }
        return py.substring(0, 1);
    }

    /**
     * 转换为数据库风格（全部小写，下划线分割）
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static String toDbStyle(String str) {
        StringBuffer sb = new StringBuffer();
        char c;
        for (int i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (Character.isLowerCase(c))
                sb.append(c);
            else {
                if (i > 0)
                    sb.append("_");
                sb.append(Character.toLowerCase(c));
            }

        }
        return sb.toString();
    }

    /**
     * 转换为Java
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static String toJavaStyle(String str) {
        boolean cahang = false;
        StringBuffer sb = new StringBuffer();
        char c;
        for (int i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (c == '_') {
                cahang = true;
            } else {
                if (cahang) {
                    c = Character.toUpperCase(c);
                    cahang = false;
                }
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 设定校验用户名及密码的正则表达式，方便扩展
     *
     * @param userName
     * @param password
     * @author laomake@hotmail.com
     */
    public static void setUserNameAndPasswordRegex(String userName, String password) {
        REGEX_USER_NAME = userName;
        UserName = Pattern.compile(REGEX_USER_NAME);

        REGEX_PASSWORD = password;
        Password = Pattern.compile(REGEX_PASSWORD);
    }

    /**
     * 判断字符串是否符合用户名格式
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isLoginName(String str) {
        Boolean matcher = false;
        if (StringUtils.isBlank(str))
            matcher = UserName.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否符合密码格式
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isPassword(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Password.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否符合手机号格式
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isMobile(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Mobile.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否符合邮件地址格式
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isEmail(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Email.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否为URL
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isUrl(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Url.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否符合身份证格式
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isIdCard(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str)) {
            if (str.length() == 18)
                matcher = IDcard.matcher(str).matches();
            else if (str.length() == 15)
                matcher = IDcardOld.matcher(str).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否为纯数字
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isNumber(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Number.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断字符串是否为纯中文
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean isChiness(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = ChinessAll.matcher(str).matches();
        return matcher;
    }

    /**
     * 判断当前请求是否来自移动端
     *
     * @param ua
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean fromMobile(String ua) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(ua)) {
            matcher = FromPhone.matcher(ua).matches();
            if (!matcher)
                matcher = FromTab.matcher(ua).matches();
        }
        return matcher;
    }

    /**
     * 判断字符串是否包含中文
     *
     * @param str
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean containChiness(String str) {
        Boolean matcher = false;
        if (StringUtils.isNotBlank(str))
            matcher = Chiness.matcher(str).matches();
        return matcher;
    }

    /**
     * 去除字符串中的Emoji字符
     *
     * @param content
     * @return
     * @author laomake@hotmail.com
     */
    public static String cleanEmoji(String content) {
        if (containsEmoji(content)) {
            StringBuilder sb = new StringBuilder();
            int len = content.length();
            for (int i = 0; i < len; i++) {
                char character = content.charAt(i);
                if (notEmoji(character))
                    sb.append(character);
            }
            content = sb.toString();
        }
        return content;
    }

    /**
     * 判断字符串中数否包含Emoji字符串
     *
     * @param content
     * @return
     * @author laomake@hotmail.com
     */
    public static Boolean containsEmoji(String content) {
        boolean containsEmoji = false;
        if (StringUtils.isNotBlank(content)) {
            int len = content.length();
            for (int i = 0; i < len; i++) {
                containsEmoji = !notEmoji(content.charAt(i));
                if (containsEmoji)
                    break;
            }
        }
        return containsEmoji;
    }

    /**
     * 判断字符是否为Emoji
     *
     * @param content
     * @return
     * @author laomake@hotmail.com
     */
    private static Boolean notEmoji(char content) {
        Boolean notEmoji = (content == 0x0) ||
                (content == 0x9) ||
                (content == 0xA) ||
                (content == 0xD) ||
                ((content >= 0x20) && (content <= 0xD7FF)) ||
                ((content >= 0xE000) && (content <= 0xFFFD)) ||
                ((content >= 0x10000) && (content <= 0x10FFFF));
        return notEmoji;
    }

    /**
     * 获取一个字节的位信息
     * @param data
     * @param position
     * @return
     */
    public static int getBit(byte data, int position){
        return switch (position) {
            case 0 -> (data & 0x01) == 0x01 ? 1 : 0;
            case 1 -> (data & 0x02) == 0x02 ? 1 : 0;
            case 2 -> (data & 0x04) == 0x04 ? 1 : 0;
            case 3 -> (data & 0x08) == 0x08 ? 1 : 0;
            case 4 -> (data & 0x10) == 0x10 ? 1 : 0;
            case 5 -> (data & 0x20) == 0x20 ? 1 : 0;
            case 6 -> (data & 0x40) == 0x40 ? 1 : 0;
            case 7 -> (data & 0x80) == 0x80 ? 1 : 0;
            default -> 0;
        };
    }

    /**
     * 提取整型值
     * @param text
     * @return
     */
    public static Integer getInteger(String text){
        if(!isNumber(text)){
            return null;
        }
        text = text.trim();
        return Integer.valueOf(text);
    }

    /**
     * 提取整型值
     * @param text
     * @return
     */
    public static Long getLong(String text){
        if(!isNumber(text)){
            return null;
        }
        text = text.trim();
        return Long.valueOf(text);
    }

    /**
     *
     * @param text
     * @return
     */
    public static Double getDouble(String text){
        if(!isNumber(text)){
            return null;
        }
        text = text.trim();
        return Double.valueOf(text);
    }

    /**
     * 提取浮点型值，指定精度
     * @param text
     * @param scale
     * @return
     */
    public static Double getDouble(String text, int scale){
        if(!isNumber(text)){
            return null;
        }
        text = text.trim();
        return getDouble(getDouble(text), scale);
    }

    /**
     * 设置浮点数精度
     * @param value
     * @param scale
     * @return
     */
    public static Double getDouble(double value, int scale){
        return BigDecimal.valueOf(value).setScale(scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 提取布尔型值
     * @param text
     * @return
     */
    public static Boolean getBoolean(String text){
        if(StringUtils.isBlank(text)){
            return null;
        }
        Boolean bool = null;
        text = text.trim().toLowerCase();
        bool = switch (text) {
            case "true", "t", "1", "是" -> true;
            default -> false;
        };
        return bool;
    }

    /**
     * 将时间戳转换为日期
     * @param text
     * @return
     */
    public static String timeStampToDate(String text){
        if(StringUtils.isBlank(text)){
            return null;
        }

        text = text.trim();
        if(!isNumber(text)) {
            return text;
        }

        String str = text.length() == 10 ? text + "000" : text;
        try {
            Long time = Long.parseLong(str);
            str = timeStampToDate(time);
        } catch (Exception e) {
            log.warn("日期解析错误：{}", text);
        }

        return str;
    }

    /**
     * 将时间戳转换为日期
     * @param time
     * @return
     */
    public static String timeStampToDate(Long time){
        if(time == null){
            return null;
        }
        String str = null;
        try {
            Date date = new Date(time);
            str = DateUtil.format(date, DatePattern.NORM_DATE_PATTERN);
        } catch (Exception e) {
            log.warn("日期解析错误：", e);
        }

        return str;
    }

    /**
     * 将时间戳转换为日期和时间
     * @param text
     * @return
     */
    public static String timeStampToDateTime(String text){
        if(text == null){
            return null;
        }

        text = text.trim();
        if(!isNumber(text)) {
            return text;
        }

        String str = text.length() == 10 ? text + "000" : text;
        try {
            Long time = Long.parseLong(str);
            Date date = new Date(time);
            str = DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN);
        } catch (NumberFormatException e) {
            log.warn("日期解析错误：{}", text);
        }

        return str;
    }

    /**
     * 将unicode字符转换为中文
     * @param text
     * @return
     */
    public static String convertUnicodeToChinese(String text) {
        Matcher matcher = PATTERN_UNICODE.matcher(text);

        while (matcher.find()) {
            String unicodeFull = matcher.group(1); // 匹配出的每个字的unicode，比如\u67e5
            String unicodeNum = matcher.group(2); // 匹配出每个字的数字，比如\u67e5，会匹配出67e5

            // 将匹配出的数字按照16进制转换为10进制，转换为char类型，就是对应的正常字符了
            char singleChar = (char) Integer.parseInt(unicodeNum, 16);

            // 替换原始字符串中的unicode码
            text = text.replace(unicodeFull, singleChar + "");
        }
        return text;
    }
}
